﻿/*
 *  This file is part of SXAPI.
 *
 *  SXAPI is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, version 3 of the License.

 *  SXAPI is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with SXAPI.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.CompilerServices;

namespace StackExchangeApi
{
    /// <summary>
    /// Exposes global configuration functionality
    /// for SXAPI.
    /// 
    /// Of most significance is SXAPI.Initialize(...),
    /// as it must be invoked before any other functionality 
    /// can be used.
    /// </summary>
    public static class SXAPI
    {
        internal static bool Initialized { get; set; }

        /// <summary>
        /// Initializes SXAPI.
        /// 
        /// Call before using any other SXAPI classes or
        /// functions.
        /// 
        /// The information provided is used to identify your application
        /// to any "Trilogy Sites" you query.  This allows the traffic 
        /// generated by your application to be separated (in theory)
        /// from other application's and normal web traffic.
        /// 
        /// Contact allows the operators of a "Trilogy Site" to contact
        /// you in the event your application is poorly behaving.  It is suggested
        /// that you use a "mailto:email@domain.tld" Uri during initial development.
        /// Switching to a proper website (ie. "http://www.example.com") after initial
        /// release is acceptable, provide that site exposes some method of contacting
        /// the developers.
        /// </summary>
        /// <param name="applicationName">Your application name</param>
        /// <param name="contact">A contact Uri, must be one of the following schemes: HTTP, HTTPS, or MAILTO.</param>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public static void Initialize(String applicationName, Uri contact)
        {
            if (Initialized)
            {
                throw new DoubleInitializationException();
            }
            ValidateInitializeParameters(applicationName, contact);

            ConnectionMediator.UserAgent =
                String.Format(
                    CultureInfo.InvariantCulture,
                    "{0} [contact at {1}]",
                    applicationName,
                    contact.AbsoluteUri);

            Initialized = true;
        }

        /// <summary>
        /// It is expected that no consumers will ever need to
        /// dispose of SXAPI, given that it doesn't actually
        /// consume any resources while idle.
        /// 
        /// However, for development purposes...
        /// </summary>
        internal static void Uninitialize()
        {
            Initialized = false;

            UserCache.Clear();
            AnswerCache.Clear();
            QuestionCache.Clear();
        }

        /// <summary>
        /// Initialize is sufficiently important that stringent parameter validation
        /// needs to be done.
        /// 
        /// Since its large and messy, it was moved to this method.
        /// </summary>
        /// <param name="applicationName">Application name to validate</param>
        /// <param name="contact">Contact uri to validate</param>
        private static void ValidateInitializeParameters(String applicationName, Uri contact)
        {
            if (contact == null)
            {
                throw new ArgumentNullException("contact");
            }

            if (contact.Scheme != "http" && contact.Scheme != "https" && contact.Scheme != "mailto")
            {
                throw new ArgumentException("contact must be of the following schemes: http, https, or mailto");
            }

            if (String.IsNullOrEmpty(applicationName))
            {
                throw new ArgumentException("applicationName cannot be null or empty");
            }

            if (contact.Scheme == "mailto")
            {
                if (String.IsNullOrEmpty(contact.UserInfo) || String.IsNullOrEmpty(contact.Host))
                {
                    throw new ArgumentException("contact using mailto scheme must contain a well-formed e-mail address");
                }
            }
        }
    }
}
